package com.atguigu.tingshu.search.service.impl;

import cn.hutool.core.util.PageUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldSort;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.*;
import co.elastic.clients.json.JsonData;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.BaseCategory3;
import com.atguigu.tingshu.model.album.BaseCategoryView;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepositoy;
import com.atguigu.tingshu.search.repository.SuggestIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexSearchVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumIndexRepositoy albumIndexRepositoy;
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private CategoryFeignClient categoryFeignClient;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private SuggestIndexRepository suggestIndexRepository;
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Override
    @SneakyThrows
    public void upperAlbum(Long albumId) {
        // 构建AlbumInfoIndex对象
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex() ;

        CompletableFuture<AlbumInfo> cf1 = CompletableFuture.supplyAsync(() -> {

            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            AlbumInfo albumInfo = albumInfoResult.getData();
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);        // 设置专辑的基本数据
            albumInfoIndex.setIsFinished(String.valueOf(albumInfo.getIsFinished()));

            // 给AlbumInfoIndex对象设置专辑属性值
            List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
            List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueVoList.stream().map(albumAttributeValue -> {
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                return attributeValueIndex;
            }).collect(Collectors.toList());
            albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
            log.info("根据专辑的id查询专辑的基本数据和专辑属性值数据....");

            return albumInfo;

        } , threadPoolExecutor);


        // 根据三级分类的id查询分类数据
        CompletableFuture<Void> cf2 = cf1.thenAcceptAsync(albumInfo -> {

            Long category3Id = albumInfo.getCategory3Id();
            Result<BaseCategoryView> categoryViewResult = categoryFeignClient.getCategoryView(category3Id);
            BaseCategoryView baseCategoryView = categoryViewResult.getData();
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
            albumInfoIndex.setCategory3Id(category3Id);
            log.info("根据三级分类的id查询分类数据....");

        } , threadPoolExecutor);


        // 根据专辑的id查询专辑的统计数据
        CompletableFuture<Void> cf3 = CompletableFuture.runAsync(() -> {

            Result<AlbumStatVo> albumStatVoResult = albumInfoFeignClient.getAlbumStatVo(Long.valueOf(albumId));
            AlbumStatVo albumStatVo = albumStatVoResult.getData();
            Integer playStatNum = albumStatVo.getPlayStatNum();
            Integer subscribeStatNum = albumStatVo.getSubscribeStatNum();
            Integer buyStatNum = albumStatVo.getBuyStatNum();
            Integer commentStatNum = albumStatVo.getCommentStatNum();
            albumInfoIndex.setPlayStatNum(playStatNum);
            albumInfoIndex.setSubscribeStatNum(subscribeStatNum);
            albumInfoIndex.setBuyStatNum(buyStatNum);
            albumInfoIndex.setCommentStatNum(commentStatNum);
            int hotScore = playStatNum * 1 + subscribeStatNum * 2 + buyStatNum * 3 + commentStatNum * 4;
            albumInfoIndex.setHotScore(Double.valueOf(String.valueOf(hotScore)));
            log.info("根据专辑的id查询专辑的统计数据....");

        }, threadPoolExecutor);


        // 根据专辑的作者id查询用户数据
        CompletableFuture<Void> cf4 = cf1.thenAcceptAsync(albumInfo -> {

            Result<UserInfo> userInfoResult = userInfoFeignClient.getUserInfoVo(albumInfo.getUserId());
            UserInfo userInfo = userInfoResult.getData();
            albumInfoIndex.setAnnouncerName(userInfo.getNickname());
            log.info("根据专辑的作者id查询用户数据....");

        }, threadPoolExecutor);

        CompletableFuture.allOf(cf1 , cf2 , cf3 , cf4).join() ;     // 把多个任务组合起来
        System.out.println(albumInfoIndex);
        // 调用持久层的接口方法，把数据保存到ES索引库中
        albumIndexRepositoy.save(albumInfoIndex) ;
        // 初始化自动补全查询的索引库
        CompletableFuture.runAsync(() -> {
            initSuggestionInfo(albumInfoIndex) ;
        });
        //todo 缓存优化——布隆过滤器
        //将专辑id保存到布隆过滤器
        RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);
        log.info("把专辑id为：{} 添加到布隆过滤器中……",albumId);
    }
    private void initSuggestionInfo(AlbumInfoIndex albumInfoIndex) {
        //把专辑的标题保存到自动补全查询索引库中
        SuggestIndex albumTitleSuggestIndex = new SuggestIndex();
        albumTitleSuggestIndex.setId(UUID.randomUUID().toString().replaceAll("-",""));
        String albumTitle = albumInfoIndex.getAlbumTitle();
        albumTitleSuggestIndex.setTitle(albumTitle);
        albumTitleSuggestIndex.setKeyword(new Completion(new String[]{albumTitle}));
        albumTitleSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumTitle)}));
        albumTitleSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumTitle)})) ;
        suggestIndexRepository.save(albumTitleSuggestIndex);
        //把专辑的简介保存到自动补全查询索引库中
        SuggestIndex albumIntroSuggestIndex = new SuggestIndex();
        albumIntroSuggestIndex.setId(UUID.randomUUID().toString().replaceAll("-",""));
        String albumIntro = albumInfoIndex.getAlbumIntro();
        albumIntroSuggestIndex.setTitle(albumIntro);
        albumIntroSuggestIndex.setKeyword(new Completion(new String[]{albumIntro}));
        albumIntroSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumIntro)}));
        albumIntroSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumIntro)}));
        suggestIndexRepository.save(albumIntroSuggestIndex);
        //把专辑的作者名称保存到自动补全查询索引库中
        SuggestIndex announcerNameSuggestIndex = new SuggestIndex();
        announcerNameSuggestIndex.setId(UUID.randomUUID().toString().replaceAll("" +
                "-",""));
        String announceName = albumInfoIndex.getAnnouncerName();
        announcerNameSuggestIndex.setTitle(announceName);
        announcerNameSuggestIndex.setKeyword(new Completion(new String[]{announceName}));
        announcerNameSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(announceName)}));
        announcerNameSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(announceName)}));
        suggestIndexRepository.save(announcerNameSuggestIndex);
    }
    @Override
    public void lowerAlbum(Long albumId) {
        //从ES库中删除对应的专辑
        albumIndexRepositoy.deleteById(albumId);
        /**todo
         * 布隆过滤器不能删除数据，进行布隆过滤器的重建
         * 1、创建一个新的布隆过滤器
         * 2、从ES索引库中查询出所有的专辑id，然后把专辑id保存到新的布隆过滤器
         * 3、删除旧的布隆过滤器，然后对新的布隆过滤器命名——>防止删除和重命名之间有其他请求使用布隆过滤器，需要保证删除和重命名操作的原子性（使用lua脚本）
         */
        //创建一个新的布隆过滤器
        RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        //尝试初始化布隆过滤器，预期容纳1,000,000个元素，且误报率为0.01%
        bloomFilter.tryInit(1000000,0.0001);
        //从ES索引库中查询出所有的专辑id，然后把专辑id保存到新的布隆过滤器
        albumIndexRepositoy.findAll().forEach(albumInfoIndex -> {
            bloomFilter.add(albumInfoIndex.getId());
            log.info("新的布隆过滤器创建成功了……");
        //删除旧的布隆过滤器，然后对新的布隆过滤器命名
            //定义lua脚本
            String script = "redis.call(\"del\" , KEYS[1])\n" +
                    "redis.call(\"del\" , \"{\"..KEYS[1]..\"}:\"..\"config\")\n" +
                    "redis.call(\"rename\" , KEYS[2] , KEYS[1])\n" +
                    "redis.call(\"rename\" , \"{\"..KEYS[2]..\"}:\"..\"config\" , \"{\"..KEYS[1]..\"}:\"..\"config\")\n" +
                    "return 1" ;
            //执行lua脚本
            Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(RedisConstant.ALBUM_BLOOM_FILTER, RedisConstant.ALBUM_NEW_BLOOM_FILTER));
            log.info("删除旧的布隆过滤器(album:bloom:filter),然后对新的布隆过滤器重命名(album:bloom:filter:new)，结果为{}",result);
        });
    }

    @SneakyThrows
    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //1.构建SearchRequest对象，封装搜索请求参数
        SearchRequest searchRequest = buildSearchRequest(albumIndexQuery);
        //2.发送搜索请求
        SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        //3.构建AlbumSearchResponseVo对象进行返回
        AlbumSearchResponseVo albumSearchResponseVo = parseSearchResponse(searchResponse , albumIndexQuery) ;
        return albumSearchResponseVo;
    }

    @SneakyThrows
    @Override
    public List<AlbumInfoIndexSearchVo> channel(Long c1Id) {
        // 根据一级分类的id查询置顶的三级分类数据
        Result<List<BaseCategory3>> result = categoryFeignClient.findTopBaseCategory3(c1Id);
        List<BaseCategory3> category3List = result.getData();
        Map<Long, BaseCategory3> category3Map = category3List.stream().collect(Collectors.toMap(baseCategory3 -> baseCategory3.getId(), baseCategory3 -> baseCategory3));
        // 创建TermsQueryField对象
        List<FieldValue> fieldValueList = category3Map.keySet().stream().map(category3Id -> new FieldValue.Builder().longValue(category3Id).build()).collect(Collectors.toList());
        TermsQueryField termsQueryField = new TermsQueryField.Builder()
                .value(fieldValueList)
                .build();

        // 创建一个BoolQuery对象
        BoolQuery boolQuery = QueryBuilders.bool()
                .must(builder -> builder.term(termBuilder -> termBuilder.field("category1Id").value(c1Id)))
                .must(builder -> builder.terms(termsBuilder -> termsBuilder.field("category3Id").terms(termsQueryField)))
                .build();

        // 创建一个Query对象
        Query query = new Query.Builder().bool(boolQuery).build();

        // 创建一个SourceConfig对象
        SourceConfig sourceConfig = new SourceConfig.Builder()
                .fetch(false)
                .build();

        // 创建一个Aggregation对象
        Aggregation hotScoreAggregation = new Aggregation.Builder().topHits(
                builder -> builder.size(9).sort(sortBuilder -> sortBuilder.field(fieldBuilder -> fieldBuilder.field("hotScore")
                        .order(SortOrder.Desc)))).build();

        // 创建一个Aggregation对象
        Aggregation aggregation = new Aggregation.Builder().terms(builder -> builder.field("category3Id").size(10))
                .aggregations("topHitAgg" , hotScoreAggregation)
                .build();

        // 1、构建SearchRequest对象，封装搜索请求参数
        SearchRequest searchRequest = new SearchRequest.Builder()
                .query(query)
                .source(sourceConfig)
                .aggregations("category3IdAgg" ,aggregation )
                .build() ;

        log.info(searchRequest.toString());

        //todo 2、发送搜索请求
        SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);

        // 3、构建AlbumInfoIndexSearchVo对象进行返回
        List<AlbumInfoIndexSearchVo> albumInfoIndexSearchVos = new ArrayList<>() ;
        Map<String, Aggregate> aggregateMap = searchResponse.aggregations();
        Aggregate aggregate = aggregateMap.get("category3IdAgg");
        LongTermsAggregate longTermsAggregate = (LongTermsAggregate) aggregate._get();
        Buckets<LongTermsBucket> buckets = longTermsAggregate.buckets();
        List<LongTermsBucket> bucketList = buckets.array();
        for(LongTermsBucket longTermsBucket : bucketList) {
            AlbumInfoIndexSearchVo albumInfoIndexSearchVo = new AlbumInfoIndexSearchVo() ;
            long c3Id = longTermsBucket.key();
            BaseCategory3 baseCategory3 = category3Map.get(c3Id);
            albumInfoIndexSearchVo.setBaseCategory3(baseCategory3);

            // 获取当前这个三级分类的专辑列表数据
            Map<String, Aggregate> map = longTermsBucket.aggregations();
            Aggregate topHitAgg = map.get("topHitAgg");
            TopHitsAggregate topHitsAggregate = (TopHitsAggregate) topHitAgg._get();
            HitsMetadata<JsonData> hitsMetadata = topHitsAggregate.hits();
            List<Hit<JsonData>> hits = hitsMetadata.hits();
            List<AlbumInfoIndex> albumInfoIndexList = hits.stream().map(hit -> {
                JsonData jsonData = hit.source();
                AlbumInfoIndex albumInfoIndex = jsonData.to(AlbumInfoIndex.class);
                return albumInfoIndex;
            }).collect(Collectors.toList());
            albumInfoIndexSearchVo.setList(albumInfoIndexList);

            // 把albumInfoIndexSearchVo存储到albumInfoIndexSearchVos集合中
            albumInfoIndexSearchVos.add(albumInfoIndexSearchVo) ;

        }
        // 返回
        return albumInfoIndexSearchVos;
    }

    @SneakyThrows
    @Override
    public List<String> completeSuggest(String keyword) {
        // 创建一个Suggester对象
        Suggester suggester = new Suggester.Builder()
                .suggesters("keywordSuggest" , builder -> builder.prefix(keyword).completion(
                        completionBuilder -> completionBuilder.field("keyword").size(10).skipDuplicates(true).fuzzy(
                                fuzzyBuilder -> fuzzyBuilder.fuzziness("auto")
                        ))
                )
                .suggesters("keywordPinyinSuggest" , builder -> builder.prefix(keyword).completion(
                        completionBuilder -> completionBuilder.field("keywordPinyin").size(10).skipDuplicates(true).fuzzy(
                                fuzzyBuilder -> fuzzyBuilder.fuzziness("auto")
                        ))
                )
                .suggesters("keywordSequenceSuggest" , builder -> builder.prefix(keyword).completion(
                        completionBuilder -> completionBuilder.field("keywordSequence").size(10).skipDuplicates(true).fuzzy(
                                fuzzyBuilder -> fuzzyBuilder.fuzziness("auto")
                        ))
                )
                .build();

        // 创建SearchRequest对象
        SearchRequest searchRequest = new SearchRequest.Builder()
                .suggest(suggester)
                .build();

        // 发送请求
        SearchResponse<SuggestIndex> searchResponse = elasticsearchClient.search(searchRequest, SuggestIndex.class);

        // 从SearchResponse对象获取结果数据
        Map<String, List<Suggestion<SuggestIndex>>> suggest = searchResponse.suggest();
        List<String> result = new ArrayList<>() ;
        this.getSuggestResult(suggest , "keywordSuggest" , result) ;
        this.getSuggestResult(suggest , "keywordPinyinSuggest" , result) ;
        this.getSuggestResult(suggest , "keywordSequenceSuggest" , result) ;

        return result;
    }

    private void getSuggestResult(Map<String, List<Suggestion<SuggestIndex>>> suggest, String suggestName, List<String> result) {
        List<Suggestion<SuggestIndex>> keywordSuggest = suggest.get(suggestName);
        for(Suggestion<SuggestIndex> suggestion : keywordSuggest) {
            CompletionSuggest<SuggestIndex> completion = suggestion.completion();
            List<CompletionSuggestOption<SuggestIndex>> options = completion.options();
            for(CompletionSuggestOption<SuggestIndex> option : options) {
                SuggestIndex source = option.source();
                String title = source.getTitle();
                result.add(title) ;
            }
        }
    }

    private AlbumSearchResponseVo parseSearchResponse(SearchResponse<AlbumInfoIndex> searchResponse, AlbumIndexQuery albumIndexQuery) {
        // 从searchResponse对象中获取查询结果
        HitsMetadata<AlbumInfoIndex> hitsMetadata = searchResponse.hits();

        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo() ;

        List<Hit<AlbumInfoIndex>> hits = hitsMetadata.hits();
        List<AlbumInfoIndexVo> albumInfoIndexVoList = hits.stream().map(hit -> {
            AlbumInfoIndex albumInfoIndex = hit.source();       // 获取到了原始文档数据
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);

            // 获取高亮的结果数据
            Map<String, List<String>> highlighted = hit.highlight();
            if(!CollectionUtils.isEmpty(highlighted)) {
                List<String> albumTitleList = highlighted.get("albumTitle");
                if(!CollectionUtils.isEmpty(albumTitleList)) {
                    String highlightedAlbumTitle = albumTitleList.get(0) ;
                    albumInfoIndexVo.setAlbumTitle(highlightedAlbumTitle);
                }
            }

            return albumInfoIndexVo;
        }).collect(Collectors.toList());
        albumSearchResponseVo.setList(albumInfoIndexVoList);        // 当前页数据

        // 设置分页参数
        long total = hitsMetadata.total().value();
        albumSearchResponseVo.setTotal(total);
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        int totalPage = PageUtil.totalPage(total, albumIndexQuery.getPageSize());
        albumSearchResponseVo.setTotalPages(Long.parseLong(String.valueOf(totalPage)));

        // 返回
        return albumSearchResponseVo ;
    }

    private SearchRequest buildSearchRequest(AlbumIndexQuery albumIndexQuery) {
        //创建BoolQuery对象
        BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();
        //设置搜索关键字的搜索条件
        String keyword = albumIndexQuery.getKeyword();
        if(!StringUtils.isEmpty(keyword)) {
            boolQueryBuilder.must(builder -> builder.multiMatch(
                    multiMatchBuilder -> multiMatchBuilder.fields("albumTitle" , "albumIntro").query(keyword))) ;
        }else {
            boolQueryBuilder.must(builder -> builder.matchAll(matchAllBuilder -> matchAllBuilder)) ;
        }
        //拼接一级分类id的搜索条件
        Long category1Id = albumIndexQuery.getCategory1Id();
        if(category1Id != null) {
            boolQueryBuilder.must(builder -> builder.term(termBuilder -> termBuilder.field("category1Id").value(category1Id))) ;
        }
        //拼接二级分类id的搜索条件
        Long category2Id = albumIndexQuery.getCategory2Id();
        if(category2Id != null) {
            boolQueryBuilder.must(builder -> builder.term(termBuilder -> termBuilder.field("category2Id").value(category2Id))) ;
        }
        //拼接三级分类id的搜索条件
        Long category3Id = albumIndexQuery.getCategory3Id();
        if(category3Id != null) {
            boolQueryBuilder.must(builder -> builder.term(termBuilder -> termBuilder.field("category3Id").value(category3Id))) ;
        }
        //拼接专辑属性值的搜索条件
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if(!CollectionUtils.isEmpty(attributeList)) {

            for (String attrInfo : attributeList) {

                String[] attrInfoArr = attrInfo.split(":");
                String attrId = attrInfoArr[0];
                String valueId = attrInfoArr[1];
                // 创建一个BoolQuery
                BoolQuery boolQuery = new BoolQuery.Builder()
                        .must(builder -> builder.term(termBuilder -> termBuilder.field("attributeValueIndexList.attributeId").value(attrId)))
                        .must(builder -> builder.term(termBuilder -> termBuilder.field("attributeValueIndexList.valueId").value(valueId)))
                        .build();

                NestedQuery nestedQuery = new NestedQuery.Builder()
                        .path("attributeValueIndexList")
                        .query(boolQuery._toQuery())
                        .build();
                boolQueryBuilder.must(builder -> builder.nested(nestedQuery));
            }
        }
        //创建一个Query对象，封装搜索的请求方式
        Query query = new Query.Builder().bool(boolQueryBuilder.build()).build();
        //创建SearchRequest.build对象
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index("albuminfo") ;
        builder.query(query) ;
        //构建排序的参数
        FieldSort.Builder fieldSortBuilder = new FieldSort.Builder();
        String order = albumIndexQuery.getOrder();
        if(!StringUtils.isEmpty(order)) {
            String[] orderInfoArr = order.split(":");
            String field = orderInfoArr[0] ;
            String direction = orderInfoArr[1] ;
            SortOrder sortOrder = direction.equalsIgnoreCase("asc") ? SortOrder.Asc : SortOrder.Desc ;
            switch (field) {
                case "1" :
                    fieldSortBuilder.field("hotScore").order(sortOrder) ;
                    break;
                case "2" :
                    fieldSortBuilder.field("playStatNum").order(sortOrder) ;
                    break;
                case "3" :
                    fieldSortBuilder.field("createTime").order(sortOrder) ;
                    break;
            }
        }else {
            fieldSortBuilder.field("hotScore").order(SortOrder.Desc) ;      //  设置的默认的排序方式
        }
        SortOptions sortOptions = new SortOptions.Builder()
                .field(fieldSortBuilder.build())
                .build() ;
        builder.sort(sortOptions) ;
        //设置分页参数
        Integer from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize() ;
        Integer size = albumIndexQuery.getPageSize() ;
        builder.from(from) ;
        builder.size(size) ;
        //设置高亮参数
        if(!StringUtils.isEmpty(keyword)) {

            // 创建一个Highlight对象
            Highlight highlight = new Highlight.Builder()
                    .fields("albumTitle" , highlightFieldBuilder -> highlightFieldBuilder.preTags("<font color='red'>").postTags("</font>"))
                    .build();
            builder.highlight(highlight) ;

        }
        //返回
        return builder.build();
    }


}
